home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / aplictns / graph.6 < prev    next >
Internet Message Format  |  1989-11-13  |  64KB

  1. Path: xanth!lll-winken!ctrsol!gem.mps.ohio-state.edu!brutus.cs.uiuc.edu!wuarchive!texbell!texsun!newstop!sun!swap!page
  2. From: page%swap@Sun.COM (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i209:  graph - plot mathematical functions, Part06/07
  5. Message-ID: <127787@sun.Eng.Sun.COM>
  6. Date: 13 Nov 89 02:32:50 GMT
  7. Sender: news@sun.Eng.Sun.COM
  8. Lines: 1900
  9. Approved: page@sun.com
  10.  
  11. Submitted-by: dg3i+@andrew.cmu.edu (David Gay)
  12. Posting-number: Volume 89, Issue 209
  13. Archive-name: applications/graph.6
  14.  
  15. # This is a shell archive.
  16. # Remove anything above and including the cut line.
  17. # Then run the rest of the file through 'sh'.
  18. # Unpacked files will be owned by you and have default permissions.
  19. #----cut here-----cut here-----cut here-----cut here----#
  20. #!/bin/sh
  21. # shar: SHell ARchive
  22. # Run the following text through 'sh' to create:
  23. #    object.guidelines
  24. #    object.h
  25. #    pos.c
  26. #    r_of_t.c
  27. #    r_t.c
  28. #    smallsym.c
  29. #    tracker.c
  30. #    tracker.h
  31. #    tracker.readme
  32. # This is archive 6 of a 7-part kit.
  33. # This archive created: Sun Nov 12 18:23:31 1989
  34. echo "extracting object.guidelines"
  35. sed 's/^X//' << \SHAR_EOF > object.guidelines
  36. XThere are actually two types of objects (should I have two main object
  37. Xclasses, inherited from a common root ?):
  38. X
  39. Xa) Objects which are visual (labels, lines, rectangles)
  40. Xb) Objects which exist semi-independtly from the graph (functions)
  41. X
  42. XObjects of class b are selectable even if the graph is invalid, they have a
  43. Xname. Hence, as they can be selected other than by clicking on them, they are
  44. Xallowed to be 'invalid' (not displayable). All this is not allowed for
  45. Xclass a). The name and ok fields serve these purposes, name must be a null
  46. Xstring and ok true for class a).
  47. X
  48. XThe methods will be called as expected: all created objects will be deleted,
  49. Xselects will be followed by deselects, the sequence for down/move/up is
  50. X
  51. Xdown, move, move, ..., up
  52. X
  53. Xselect will be called if down returns true (the actual sequence is therefore:
  54. X- if down returns FALSE   down
  55. X- if down returns TRUE    down, select, move, move, ..., up
  56. X)
  57. X
  58. XThe graph will be in a valid state (ok, window coords exisiting) when
  59. Xdown/move/up/draw are called, but not necessarily so for all the other calls.
  60. X
  61. X
  62. XPublic fields:
  63. X--------------
  64. X
  65. Xnode node: used to keep objects in a list
  66. Xstruct graph *g: the graph in which this object is
  67. Xint ok: object in a valid state ?
  68. Xint mx, my: These specify an offset to apply to the position of the mouse
  69. Xwhile it is moved around. This allows you to have an object picked up and
  70. Xmoved around by an arbitray point (the mouse will maintain the same position
  71. Xrelative to the objects origin thoughout, eg when dragging an object).
  72. X
  73. Xmethods:
  74. X--------
  75. X
  76. Xdelete      no comment
  77. X
  78. Xselect      you have been selected. You should probbaly highlight yourself.
  79. X
  80. Xdeselect    Deselect yourself (dehighlight ?), return TRUE if the graph
  81. X            needs redrawing (eg if you can't unhighlight cleanly).
  82. X
  83. Xdown        Return true if graph's coordinates (in g->s.x,y) are inside you.
  84. X            If you answer TRUE, you will be selected (cf select).
  85. X
  86. Xmove        The mouse has moved. Do what you want (resize, drag, nothing).
  87. X            Called only if you answered TRUE to down (Coordinates as above).
  88. X
  89. Xup          The mouse has been released. return TRUE if the graph needs
  90. X            redrawing (eg if you moved).
  91. X
  92. Xedit        Allow the user detailed control over your placement, ... Return
  93. X            TRUE if the object changed.
  94. X
  95. Xdraw        Display thyself ! allow_mes is FALSE if called during refresh
  96. X            (this mainly means that you can't display error messages).
  97. X
  98. Ximprove     Improve your appearance (for functions mainly). Return TRUE if
  99. X            graph needs redrawing.
  100. X
  101. Xf2str       Provide a concise (one line) textual description of yourself, in
  102. X            buf (maximum size: maxlen). Return buf.
  103. X
  104. Xvar_change  Is called for every object whenever a variable changes value. The
  105. X            variable that has changed is passed. You should do whatever is
  106. X            necessary to make sure that the next time you are displayed, you
  107. X            reflect the new value of the variable.
  108. X
  109. Xsave        Save yourself in the file. For the format, see load_<obj> below.
  110. X
  111. Xinform      Called for every object of a graph when it changes (for the moment,
  112. X     
  113. X            only when the dots per meter values change). This allows any
  114. X            dependent values to be recalculated, any fonts to be loaded, etc
  115. X            If this isn't possible (eg no memory left), return FALSE and
  116. X            return to your previous state, otherwise return TRUE (but keep
  117. X            enough information to return to your previous state without
  118. X            needing any resources).
  119. X
  120. Xconfirm     After an inform (to which you retuned TRUE), confirm is called
  121. X            (before anything else), with ok being TRUE to confirm the
  122. X            changes to the graph (you can now free any old resources), or
  123. X            FALSE if the changes failed (return to the old state and free
  124. X            any newly allocated resources).
  125. X            Note: if you answered FALSE.to inform, this method won't get
  126. X            called.
  127. X
  128. Xfunctions
  129. X---------
  130. XYou must also provide two functions to create the objects:
  131. X
  132. Xnew_<objname>   Create a new instance of an object of class objname. Provide
  133. X                whatever initial parameters are necessary, or prompt the user.
  134. X                The main code will obviously have to be modified to allow
  135. X                creation of ant new object type ...
  136. X
  137. Xload_<objname>  Also creates a new instance, but with ant information loaded
  138. X                from disk (The file is one of the parameters). The format, in
  139. X                the file must be:
  140. X
  141. X                <object tag> a unique short for each type of object
  142. X                <any private data>
  143. X                <object end tag> another unique short
  144. X
  145. X                When load is called, the first tag has been read. load should
  146. X                check for data integrity, and the presence of the end_tag.
  147. X                NULL should be returned as an error.
  148. X
  149. X                The tags are centralised in file.h, to avoid errors.
  150. X
  151. SHAR_EOF
  152. echo "extracting object.h"
  153. sed 's/^X//' << \SHAR_EOF > object.h
  154. X/*
  155. X *                 GRAPH, Version 1.00 - 4 August 1989
  156. X *
  157. X *            Copyright 1989, David Gay. All Rights Reserved.
  158. X *            This software is freely redistrubatable.
  159. X */
  160. X
  161. X/* The object class. All the different objects are subclasses of it */
  162. X#ifndef OBJECT_H
  163. X#define OBJECT_H
  164. X
  165. X#include <stdio.h>
  166. X#include "list.h"
  167. X#include "grph.h"
  168. X
  169. X#define FNAMELEN 20 /* Length of object name */
  170. X
  171. Xstruct object
  172. X{
  173. X    node node;
  174. X    struct graph *g; /* Which graph this object is in (g->s.x,y contains curren
  175. Xt mouse pos)*/
  176. X    char name [FNAMELEN]; /* Name (for functions only) "" otherwise */
  177. X    int ok; /* For functions only: is it displayed */
  178. X    int mx, my; /* Specify an (optional) displacement for the mouse pointer whe
  179. Xn this is selected */
  180. X    struct Region *(*delete)    (struct object *this);
  181. X    void           (*select)    (struct object *this); /* You have been selecte
  182. Xd */
  183. X    struct Region *(*deselect)  (struct object *this); /* done. does the screen
  184. X need refreshing  ? */
  185. X    int            (*down)      (struct object *this); /* User pressed button.
  186. XReturn TRUE if (x,y) is inside you */
  187. X    void           (*move)      (struct object *this);
  188. X    struct Region *(*up)        (struct object *this); /* Redraw necessary ? */
  189. X     
  190. X    int            (*edit)      (struct object *this, struct Region **ref); /*
  191. XReturns true if graph changed */
  192. X    void           (*draw)      (struct object *this, int allow_mes);
  193. X    struct Region *(*improve)   (struct object *this);
  194. X    char          *(*f2str)     (struct object *this, char *buf, int maxlen);
  195. X    void           (*var_change)(struct object *this, char *name); /* Change in
  196. X variable "name" */
  197. X    int            (*save)      (struct object *this, FILE *f);
  198. X    int            (*inform)    (struct object *this); /* Inform of changes to
  199. Xg */
  200. X    void           (*confirm)   (struct object *this, int ok); /* Confirm previ
  201. Xous changes */
  202. X};
  203. X
  204. X/* A special object, used for selecting points on screen (cross hair mode) */
  205. X/* The fields are public. Only new, down, move, up and deselect are implemented
  206. X  */
  207. Xstruct pos
  208. X{
  209. X    struct object o;
  210. X    int cross : 1;
  211. X    int rect : 1;
  212. X    double x0, y0, x1, y1;
  213. X};
  214. X
  215. Xstruct pos *new_pos(struct graph *g);
  216. X
  217. X/* A label on the graph */
  218. Xstruct label *new_label(struct graph *g, double x, double y);
  219. Xstruct label *load_label(struct graph *g, FILE *f);
  220. X
  221. X/* A function (ie f(x), r(theta), etc */
  222. Xstruct function *new_function(struct graph *g);
  223. Xstruct function *load_function(struct graph *g, FILE *f);
  224. X
  225. X#endif
  226. X
  227. SHAR_EOF
  228. echo "extracting pos.c"
  229. sed 's/^X//' << \SHAR_EOF > pos.c
  230. X/*
  231. X *                 GRAPH, Version 1.00 - 4 August 1989
  232. X *
  233. X *            Copyright 1989, David Gay. All Rights Reserved.
  234. X *            This software is freely redistrubatable.
  235. X */
  236. X
  237. X#include <exec/types.h>
  238. X#include <graphics/text.h>
  239. X#include <math.h>
  240. X
  241. X#include "object.h"
  242. X#include "object/default.h"
  243. X#include "uio.h"
  244. X#include "grph.h"
  245. X#include "coords.h"
  246. X#include "tracker.h"
  247. X
  248. X#include <proto/exec.h>
  249. X#include <proto/graphics.h>
  250. X
  251. X/*-------------------------------------------------------------------------*/
  252. X/*                        pos class implementation                         */
  253. X/*-------------------------------------------------------------------------*/
  254. X
  255. X/* Size of cross */
  256. X#define XCROSS 3
  257. X#define YCROSS 3
  258. X
  259. X/* Redraw cross/rect */
  260. Xstatic void draw_pos(struct pos *this, int allow_mes)
  261. X{
  262. X    struct graph *g = this->o.g;
  263. X    struct RastPort *rp = g->io.rw->rp;
  264. X
  265. X    SetDrMd(rp, COMPLEMENT);
  266. X    if (this->cross) /* Draw cross */
  267. X    {
  268. X        RMove(g->io.rw, this->x0, this->y0);
  269. X        Move(rp, rp->cp_x - XCROSS, rp->cp_y);
  270. X        Draw(rp, rp->cp_x + 2 * XCROSS, rp->cp_y);
  271. X        Move(rp, rp->cp_x - XCROSS, rp->cp_y - YCROSS);
  272. X        Draw(rp, rp->cp_x, rp->cp_y + 2 * YCROSS);
  273. X    }
  274. X    if (this->rect) /* Draw rectangle */
  275. X    {
  276. X        long const sx0 = ftol(g->io.rw->sx(g->io.rw, this->x0));
  277. X        long const sx1 = ftol(g->io.rw->sx(g->io.rw, this->x1));
  278. X        long const sy0 = ftol(g->io.rw->sy(g->io.rw, this->y0));
  279. X        long const sy1 = ftol(g->io.rw->sy(g->io.rw, this->y1));
  280. X        long c1 = ReadPixel(rp, sx0, sy0);
  281. X        long c2 = ReadPixel(rp, sx0, sy1);
  282. X        long c3 = ReadPixel(rp, sx1, sy0);
  283. X        long c4 = ReadPixel(rp, sx1, sy1);
  284. X
  285. X        Move(rp, sx0, sy0);
  286. X        Draw(rp, sx1, sy0);
  287. X        Draw(rp, sx1, sy1);
  288. X        Draw(rp, sx0, sy1);
  289. X        Draw(rp, sx0, sy0);
  290. X        /* Had problems with the corners ... */
  291. X        if (c1 == ReadPixel(rp, sx0, sy0)) WritePixel(rp, sx0, sy0);
  292. X        if (c2 == ReadPixel(rp, sx0, sy1)) WritePixel(rp, sx0, sy1);
  293. X        if (c3 == ReadPixel(rp, sx1, sy0)) WritePixel(rp, sx1, sy0);
  294. X        if (c4 == ReadPixel(rp, sx1, sy1)) WritePixel(rp, sx1, sy1);
  295. X    }
  296. X}
  297. X
  298. X/* The object exists only to be "selected" --> */
  299. X/* This actually deletes the object !!! */
  300. Xstatic struct Region *deselect_pos(struct pos *this)
  301. X{
  302. X    if (this->o.g->ok && this->o.g->io.rw) draw_pos(this, TRUE); /* erase */
  303. X    FreeMem(this, sizeof(struct pos));
  304. X    return NULL;
  305. X}
  306. X
  307. Xstatic int down_pos(struct pos *this)
  308. X{
  309. X    return FALSE; /* You can never select a 'pos' */
  310. X}
  311. X
  312. X/* Move, ie define rectangle */
  313. Xstatic void move_pos(struct pos *this)
  314. X{
  315. X    draw_pos(this, TRUE);   /* erase old */
  316. X    this->x1 = this->o.g->s.x;
  317. X    this->y1 = this->o.g->s.y;
  318. X    this->cross = FALSE; this->rect = TRUE; /* Not a cross any more */
  319. X    draw_pos(this, TRUE);   /* draw new */
  320. X}
  321. X
  322. X/* Rectangle is now defined */
  323. Xstatic struct Region *up_pos(struct pos *this)
  324. X{
  325. X    draw_pos(this, TRUE);
  326. X    this->x1 = this->o.g->s.x;
  327. X    this->y1 = this->o.g->s.y;
  328. X    draw_pos(this, TRUE);
  329. X
  330. X    return NULL;
  331. X}
  332. X
  333. X/* Create a rectangle/cross (starts off as a cross) */
  334. Xstruct pos *new_pos(struct graph *g)
  335. X{
  336. X    struct pos *this;
  337. X    const static struct pos def_p = {
  338. X        {
  339. X            { NULL },
  340. X            NULL, "", TRUE, 0, 0,
  341. X            (void *)uncalled, (void *)uncalled, (void *)deselect_pos, (void *)d
  342. Xown_pos, (void *)move_pos, (void *)up_pos, (void *)uncalled, (void *)draw_pos, (
  343. Xvoid *)uncalled, (void *)uncalled, (void *)uncalled, (void *)uncalled, (void *)u
  344. Xncalled,
  345. X            (void *)uncalled
  346. X        },
  347. X        TRUE, FALSE
  348. X    };
  349. X
  350. X    if (g->ok && g->io.rw)
  351. X        if (this = AllocMem(sizeof(struct pos), 0L))
  352. X        {
  353. X            *this = def_p;
  354. X            this->o.g = g;
  355. X            this->x0 = this->x1 = g->s.x;
  356. X            this->y0 = this->y1 = g->s.y;
  357. X            draw_pos(this, TRUE); /* draw it */
  358. X
  359. X            return this;
  360. X        }
  361. X        else message(g, "No memory !", (char *)NULL);
  362. X    else message(g, "No scale set", (char *)NULL);
  363. X    return NULL;
  364. X}
  365. X
  366. SHAR_EOF
  367. echo "extracting r_of_t.c"
  368. sed 's/^X//' << \SHAR_EOF > r_of_t.c
  369. X/*
  370. X *                 GRAPH, Version 1.00 - 4 August 1989
  371. X *
  372. X *            Copyright 1989, David Gay. All Rights Reserved.
  373. X *            This software is freely redistrubatable.
  374. X */
  375. X
  376. X#include <exec/types.h>
  377. X#include <intuition/intuition.h>
  378. X#include <graphics/text.h>
  379. X#include <math.h>
  380. X#include <string.h>
  381. X
  382. X#include "object.h"
  383. X#include "object/function.h"
  384. X#include "file.h"
  385. X#include "graph.h"
  386. X#include "uio.h"
  387. X#include "coords.h"
  388. X#include "list.h"
  389. X#include "grph.h"
  390. X#include "user/eval.h"
  391. X#include "user/gadgets.h"
  392. X#include "tracker.h"
  393. X
  394. X#include <proto/exec.h>
  395. X#include <proto/intuition.h>
  396. X#include <proto/graphics.h>
  397. X
  398. X/* (private) class r_of_t, inherits from function */
  399. Xstruct r_of_t {
  400. X    struct function f;
  401. X    char expr[EXPRLEN];
  402. X    value function, derivee;
  403. X};
  404. X
  405. X/* (private) class, inherits from point */
  406. Xstruct point_r_of_t
  407. X{
  408. X    point p;
  409. X    double r, theta;
  410. X};
  411. X
  412. Xtypedef struct point_r_of_t point_r_of_t;
  413. X
  414. X/*-------------------------------------------------------------------------*/
  415. X/*                      r_of_t class implementation                        */
  416. X/*-------------------------------------------------------------------------*/
  417. X
  418. X/* Is the function displayable ? */
  419. Xstatic int r_of_t_ok(const struct r_of_t *this)
  420. X{
  421. X    return this->f.min != NOVAL && this->f.max != NOVAL &&
  422. X           this->f.min < this->f.max &&
  423. X           (this->f.steps == INOVAL || this->f.steps >= 3);
  424. X}
  425. X
  426. X/* Free resources */
  427. Xstatic void destroy_r_of_t(struct r_of_t *this)
  428. X{
  429. X    free_var_list(&this->f.used);
  430. X    if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
  431. X    this->f.calc = FALSE;
  432. X    if (this->function) free_expr(this->function);
  433. X    if (this->derivee) free_expr(this->derivee);
  434. X    this->function = this->derivee = NULL;
  435. X}
  436. X
  437. X/* Init dependant parts of function */
  438. Xstatic int create_r_of_t(struct r_of_t *this)
  439. X{
  440. X    this->f.calc = FALSE;
  441. X    this->f.var.name = this->f.vname;
  442. X    this->function = compile(this->expr);
  443. X    if (eval_error != 0)
  444. X    {
  445. X        message(this->f.o.g, "Compilation error:", eval_messages[eval_error], (
  446. Xchar *)NULL);
  447. X        return FALSE;
  448. X    }
  449. X    this->derivee = differentiate(this->function, this->f.vname);
  450. X    if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  451. X    {
  452. X        message(this->f.o.g, "Differentiation error:", eval_messages[eval_error
  453. X], (char *)NULL);
  454. X        return FALSE;
  455. X    }
  456. X    if (!make_var_list(this->function, &this->f.used))
  457. X        init_var_list(&this->f.used);
  458. X    return TRUE;
  459. X}
  460. X
  461. X/* Allow user to define function */
  462. Xstatic int edit_r_of_t(struct r_of_t *this, struct Region **ref)
  463. X{
  464. X    struct Requester *req;
  465. X    struct Memory *m;
  466. X    struct Gadget *gl = NULL, *sd, *nd;
  467. X    char from[NBLEN], to[NBLEN], steps[INTLEN], expr[EXPRLEN], tname[VARLEN], c
  468. Xolour[INTLEN];
  469. X    int ret = FALSE;
  470. X
  471. X    *ref = NULL;
  472. X
  473. X    /* Create requester */
  474. X    double2str(from, this->f.min);
  475. X    double2str(to, this->f.max);
  476. X    int2str(steps, this->f.steps);
  477. X    int2str(colour, this->f.colour);
  478. X    strcpy(expr, this->expr);
  479. X    strcpy(tname, this->f.vname);
  480. X
  481. X    if ((m = NewMemory()) &&
  482. X        (req = InitReq(50, 20, 255, 145, m)) &&
  483. X        SetReqBorder(req, 1, m) &&
  484. X        AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
  485. X        AddText(&gl, 0, "r(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 25, 20,
  486. X 25, 10, TRUE, m) &&
  487. X        AddText(&gl, 0, ")=", FALSE, expr, EXPRLEN, TRUE, 0, RELVERIFY, 81, 20,
  488. X 160, 10, TRUE, m) &&
  489. X        AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 49, 40
  490. X, 80, 10, TRUE, m) &&
  491. X        AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 167, 40, 8
  492. X0, 10, TRUE, m) &&
  493. X        AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 57,
  494. X 60, 32, 10, TRUE, m) &&
  495. X        AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
  496. X56, 60, 32, 10, TRUE, m) &&
  497. X        (sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
  498. X* SELECTED, 0, 9, 80, 10, 10, m)) &&
  499. X        (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
  500. Xedisc * SELECTED, 0, 9, 100, 10, 10, m)) &&
  501. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 120, 65, 15, FALS
  502. XE, m) &&
  503. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 120, 65, 15
  504. X, FALSE, m))
  505. X    {
  506. X        SetReqGadgets(req, gl);
  507. X        if (ret = DoRequest(req, this->f.o.g, std_ghandler))
  508. X        {
  509. X            *ref = full_refresh(this->f.o.g);
  510. X
  511. X            /* Extract info */
  512. X            this->f.min = str2double(from);
  513. X            this->f.max = str2double(to);
  514. X            this->f.steps = str2int(steps);
  515. X            if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
  516. X1;
  517. X            this->f.showdisc = (sd->Flags & SELECTED) != 0;
  518. X            this->f.nicedisc = (nd->Flags & SELECTED) != 0;
  519. X            strcpy(this->expr, expr);
  520. X            strcpy(this->f.vname, tname);
  521. X
  522. X            /* Create function */
  523. X            destroy_r_of_t(this);
  524. X            if (this->f.o.ok = r_of_t_ok(this)) this->f.o.ok = create_r_of_t(th
  525. Xis);
  526. X        }
  527. X    }
  528. X    Free(m);
  529. X
  530. X    return ret;
  531. X}
  532. X
  533. X/* Calculate points of function */
  534. Xstatic int calc_r_of_t(struct r_of_t *this, int allow_mes)
  535. X{
  536. X    double theta;
  537. X    int i;
  538. X    struct graph *const g = this->f.o.g;
  539. X    int const steps = (this->f.steps == INOVAL ? DEFSTEPS : this->f.steps) - 1;
  540. X     
  541. X    double const step = (this->f.max - this->f.min) / steps;
  542. X    char func[FNAMELEN + 30];
  543. X
  544. X    new_list(&this->f.pts);
  545. X
  546. X    strcpy(func, "Can't calculate points for ");
  547. X    strcat(func, this->f.o.name);
  548. X    strcat(func, ":");
  549. X
  550. X    if (!create_quick(&this->f.var))
  551. X    {
  552. X        if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
  553. XL);
  554. X        else alert(g->io.win, func, "Couldn't create variable");
  555. X        return FALSE;
  556. X    }
  557. X
  558. X    /* Calculate steps points, spread evenly from min to max */
  559. X    for (i = 0, theta = this->f.min; i <= steps; i++, theta += step)
  560. X    {
  561. X        point_r_of_t *pt = alloc_node(this->f.sizept);
  562. X
  563. X        if (!pt)
  564. X        { /* No mem */
  565. X            free_list(&this->f.pts, this->f.sizept);
  566. X            free_quick(&this->f.var);
  567. X            if (allow_mes) message(g, func, "No memory", (char *)NULL);
  568. X            else alert(g->io.win, func, "No memory");
  569. X            return FALSE;
  570. X        }
  571. X        add_tail(&this->f.pts, pt);
  572. X
  573. X        pt->theta = theta;
  574. X        set_quick(&this->f.var, theta);
  575. X        pt->r = quick_eval(this->function);
  576. X        pt->p.state = (eval_error == 0) ? EXISTS : 0;
  577. X        /* Polar -> Rect conversion */
  578. X        pt->p.x = fabs(pt->r) * cos(theta); pt->p.y = fabs(pt->r) * sin(theta);
  579. X     
  580. X    }
  581. X    free_quick(&this->f.var);
  582. X    return TRUE;
  583. X}
  584. X
  585. X/* Try to improve look of function by adding points. If fails, decides that
  586. X   there is a discontinuity */
  587. X/* see f_of_x.c for details */
  588. Xstatic struct Region *improve_r_of_t(struct r_of_t *this)
  589. X{
  590. X    struct graph *const g = this->f.o.g;
  591. X    point_r_of_t *pt, *next;
  592. X    int ok = FALSE, iter, abort = FALSE;
  593. X    double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
  594. X    double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
  595. X    char msg[FNAMELEN + 30];
  596. X    char pass[20];
  597. X    struct Requester *req;
  598. X    struct Region *full = NULL;
  599. X
  600. X    /* Flat has no meaning when graph incorrect */
  601. X    if (!this->f.o.g->ok) flatx = flaty = 0.0;
  602. X
  603. X    if (!this->f.calc)
  604. X    {
  605. X        strcpy(msg, this->f.o.name);
  606. X        strcpy(msg, "not calculated!");
  607. X        message(g, msg, (char *)NULL);
  608. X        return NULL;
  609. X    }
  610. X    if (!this->derivee)
  611. X    {
  612. X        strcpy(msg, this->f.o.name);
  613. X        strcat(msg, " wasn't differentiable");
  614. X        message(g, msg, (char *)NULL);
  615. X        return NULL;
  616. X    }
  617. X    if (!create_quick(&this->f.var))
  618. X    {
  619. X        message(g, "Couldn't create variable", (char *)NULL);
  620. X        return NULL;
  621. X    }
  622. X
  623. X    if (!(req = abort_request(g, "Improve: Pass 1")))
  624. X        message(g, "No Memory !", (char *)NULL);
  625. X    else
  626. X    {
  627. X        full = full_refresh(this->f.o.g);
  628. X
  629. X        for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
  630. X        {
  631. X            sprintf(pass, "Improve: Pass %d", iter);
  632. X            set_abort_msg(req, pass);
  633. X            ok = TRUE;
  634. X
  635. X            for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
  636. X            {
  637. X                if (aborted(req)) { abort = TRUE; break; }
  638. X
  639. X                if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
  640. X                {
  641. X                    double dx, dy, dr, dtheta;
  642. X
  643. X                    pt->p.state |= OK;
  644. X                    pt->p.state &= ~DISC;
  645. X
  646. X                    dtheta = next->theta - pt->theta;
  647. X                    set_quick(&this->f.var, pt->theta);
  648. X                    dr = quick_eval(this->derivee);
  649. X                    if (eval_error == 0)
  650. X                    {
  651. X                        double c = cos(pt->theta);
  652. X                        double s = sin(pt->theta);
  653. X
  654. X                        /* A little elementary calculus ... */
  655. X                        dx = dr * c - pt->r * s;
  656. X                        dy = dr * s + pt->r * c;
  657. X
  658. X                        if (eval_error == 0)
  659. X                        {
  660. X                            double ecartx = next->p.x - pt->p.x;
  661. X                            double errorx = fabs(ecartx - dtheta * dx);
  662. X                            double ecarty = next->p.y - pt->p.y;
  663. X                            double errory = fabs(ecarty - dtheta * dy);
  664. X
  665. X                            /* Check both axes */
  666. X                            if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
  667. Xnicedisc || errorx > flatx)) ||
  668. X                                (errory > fabs(ecarty) * MAXERROR && (!this->f.
  669. Xnicedisc || errory > flaty)))
  670. X                            {
  671. X                                pt->p.state &= ~OK;
  672. X                                ok = FALSE;
  673. X
  674. X                                if (iter == MAXITER) pt->p.state |= DISC;
  675. X                                else /* cut interval in 2 */
  676. X                                {
  677. X                                    point_r_of_t *newpt = alloc_node(this->f.si
  678. Xzept);
  679. X
  680. X                                    if (!newpt)
  681. X                                    {
  682. X                                        nomem(g->io.win);
  683. X                                        abort = TRUE;
  684. X                                        break;
  685. X                                    }
  686. X
  687. X                                    newpt->theta = (pt->theta + next->theta) /
  688. X2;
  689. X                                    set_quick(&this->f.var, newpt->theta);
  690. X                                    newpt->r = quick_eval(this->function);
  691. X                                    newpt->p.state = (eval_error == 0) ? EXISTS
  692. X : 0;
  693. X                                    newpt->p.x = fabs(newpt->r) * cos(newpt->th
  694. Xeta);
  695. X                                    newpt->p.y = fabs(newpt->r) * sin(newpt->th
  696. Xeta);
  697. X                                    insert(&this->f.pts, newpt, pt);
  698. X                                }
  699. X                            }
  700. X                        }
  701. X                    }
  702. X                }
  703. X            }
  704. X        }
  705. X        end_abort_request(req);
  706. X    }
  707. X    free_quick(&this->f.var);
  708. X    return full;
  709. X}
  710. X
  711. X/* String representation of function */
  712. Xstatic char *f2str_r_of_t(struct r_of_t *this, char *buf, int maxlen)
  713. X{
  714. X    buf[maxlen - 1] = '\0';
  715. X    strncpy(buf, "polar ", maxlen - 1);
  716. X    strncat(buf, this->f.o.name, maxlen - strlen(buf) - 1);
  717. X    strncat(buf, "(", maxlen - strlen(buf) - 1);
  718. X    strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  719. X    strncat(buf, ")=", maxlen - strlen(buf) - 1);
  720. X    strncat(buf, this->expr, maxlen - strlen(buf) - 1);
  721. X
  722. X    return buf;
  723. X}
  724. X
  725. Xstatic int save_r_of_t(struct r_of_t *this, FILE *f)
  726. X{
  727. X    short tag = R_OF_T_TAG;
  728. X    short end = R_OF_T_END;
  729. X
  730. X    return WRITE(f, tag) &&
  731. X           WRITE(f, this->expr) &&
  732. X           WRITE(f, end);
  733. X}
  734. X
  735. X/* free function */
  736. Xstatic struct Region *delete_r_of_t(struct r_of_t *this)
  737. X{
  738. X    struct Region *full = full_refresh(this->f.o.g);
  739. X
  740. X    destroy_r_of_t(this);
  741. X    FreeMem(this, sizeof(struct r_of_t));
  742. X
  743. X    return full;
  744. X}
  745. X
  746. X/* Create a new function */
  747. Xstruct r_of_t *new_r_of_t(struct graph *g, char *name)
  748. X{
  749. X    struct r_of_t *this = AllocMem(sizeof(struct r_of_t), MEMF_CLEAR);
  750. X
  751. X    if (this)
  752. X    {
  753. X        /* Standard init */
  754. X        init_function(&this->f, g, name);
  755. X        /* Local methods */
  756. X        this->f.o.delete = (void *)delete_r_of_t;
  757. X        this->f.o.edit = (void *)edit_r_of_t;
  758. X        this->f.o.improve = (void *)improve_r_of_t;
  759. X        this->f.o.f2str = (void *)f2str_r_of_t;
  760. X        this->f.calcf = (void *)calc_r_of_t;
  761. X        this->f.save = (void *)save_r_of_t;
  762. X        this->f.sizept = sizeof(point_r_of_t);
  763. X        init_var_list(&this->f.used);
  764. X        return this;
  765. X    }
  766. X    message(g, "Couldn't create function:", "No memory", (char *)NULL);
  767. X    return NULL;
  768. X}
  769. X
  770. X/* Save local data to file */
  771. X/* load from file */
  772. Xstruct r_of_t *load_r_of_t(struct graph *g, FILE *f)
  773. X{
  774. X    struct r_of_t *this = new_r_of_t(g, "");
  775. X
  776. X    if (this)
  777. X    {
  778. X        short end;
  779. X
  780. X        /* Read local data */
  781. X        if (READ(f, this->expr) &&
  782. X            READ(f, end) &&
  783. X            end == R_OF_T_END)
  784. X        {
  785. X            load_rest(&this->f, f); /* Read standard data */
  786. X            if (this->f.o.ok = r_of_t_ok(this)) this->f.o.ok = create_r_of_t(th
  787. Xis);
  788. X
  789. X            return this;
  790. X        }
  791. X        delete_r_of_t(this);
  792. X    }
  793. X    return NULL;
  794. X}
  795. X
  796. SHAR_EOF
  797. echo "extracting r_t.c"
  798. sed 's/^X//' << \SHAR_EOF > r_t.c
  799. X/*
  800. X *                 GRAPH, Version 1.00 - 4 August 1989
  801. X *
  802. X *            Copyright 1989, David Gay. All Rights Reserved.
  803. X *            This software is freely redistrubatable.
  804. X */
  805. X
  806. X#include <exec/types.h>
  807. X#include <intuition/intuition.h>
  808. X#include <graphics/text.h>
  809. X#include <math.h>
  810. X#include <string.h>
  811. X
  812. X#include "object.h"
  813. X#include "object/function.h"
  814. X#include "file.h"
  815. X#include "graph.h"
  816. X#include "uio.h"
  817. X#include "coords.h"
  818. X#include "list.h"
  819. X#include "grph.h"
  820. X#include "user/eval.h"
  821. X#include "user/gadgets.h"
  822. X#include "tracker.h"
  823. X
  824. X#include <proto/exec.h>
  825. X#include <proto/intuition.h>
  826. X#include <proto/graphics.h>
  827. X
  828. X/* (private) class r_t, inherits from function */
  829. Xstruct r_t {
  830. X    struct function f;
  831. X    char r[EXPRLEN], theta[EXPRLEN];
  832. X    value r_t, theta_t, dr, dtheta;
  833. X};
  834. X
  835. X/* (private) class, inherits from point */
  836. Xstruct point_r_t {
  837. X    point p;
  838. X    double r, theta, t;
  839. X};
  840. X
  841. Xtypedef struct point_r_t point_r_t;
  842. X
  843. X/*-------------------------------------------------------------------------*/
  844. X/*                        r_t class implementation                         */
  845. X/*-------------------------------------------------------------------------*/
  846. X
  847. X/* Is the function displayable ? */
  848. Xstatic int r_t_ok(const struct r_t *this)
  849. X{
  850. X    return this->f.min != NOVAL && this->f.max != NOVAL &&
  851. X           this->f.min < this->f.max &&
  852. X           (this->f.steps == INOVAL || this->f.steps >= 3);
  853. X}
  854. X
  855. X/* Free resources */
  856. Xstatic void destroy_r_t(struct r_t *this)
  857. X{
  858. X    free_var_list(&this->f.used);
  859. X    if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
  860. X    this->f.calc = FALSE;
  861. X    if (this->r_t) free_expr(this->r_t);
  862. X    if (this->dr) free_expr(this->dr);
  863. X    if (this->theta_t) free_expr(this->theta_t);
  864. X    if (this->dtheta) free_expr(this->dtheta);
  865. X    this->theta_t = this->r_t = this->dtheta = this->dr = NULL;
  866. X}
  867. X
  868. X/* Init dependant parts of function */
  869. Xstatic int create_r_t(struct r_t *this)
  870. X{
  871. X    this->f.calc = FALSE;
  872. X    this->f.var.name = this->f.vname;
  873. X    this->r_t = compile(this->r);
  874. X    if (eval_error != 0)
  875. X    {
  876. X        message(this->f.o.g, "Compilation error in x(t):", eval_messages[eval_e
  877. Xrror], (char *)NULL);
  878. X        return FALSE;
  879. X    }
  880. X    this->dr = differentiate(this->r_t, this->f.vname);
  881. X    if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  882. X    {
  883. X        message(this->f.o.g, "Differentiation error (x):", eval_messages[eval_e
  884. Xrror], (char *)NULL);
  885. X        return FALSE;
  886. X    }
  887. X    this->theta_t = compile(this->theta);
  888. X    if (eval_error != 0)
  889. X    {
  890. X        message(this->f.o.g, "Compilation error in y(t):", eval_messages[eval_e
  891. Xrror], (char *)NULL);
  892. X        return FALSE;
  893. X    }
  894. X    this->dtheta = differentiate(this->theta_t, this->f.vname);
  895. X    if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  896. X    {
  897. X        message(this->f.o.g, "Differentiation error(y):", eval_messages[eval_er
  898. Xror], (char *)NULL);
  899. X        return FALSE;
  900. X    }
  901. X    if (!make_var_list(this->r_t, &this->f.used) || !make_var_list(this->theta_
  902. Xt, &this->f.used))
  903. X        init_var_list(&this->f.used);
  904. X    return TRUE;
  905. X}
  906. X
  907. X/* Allow user to define function */
  908. Xstatic int edit_r_t(struct r_t *this, struct Region **ref)
  909. X{
  910. X    struct Requester *req;
  911. X    struct Memory *m;
  912. X    struct Gadget *gl = NULL, *sd, *nd;
  913. X    char from[NBLEN], to[NBLEN], steps[INTLEN], r[EXPRLEN], theta[EXPRLEN], tna
  914. Xme[VARLEN], colour[INTLEN];
  915. X    int ret = FALSE;
  916. X
  917. X    *ref = NULL;
  918. X
  919. X    /* Create requester */
  920. X    double2str(from, this->f.min);
  921. X    double2str(to, this->f.max);
  922. X    int2str(steps, this->f.steps);
  923. X    int2str(colour, this->f.colour);
  924. X    strcpy(r, this->r);
  925. X    strcpy(theta, this->theta);
  926. X    strcpy(tname, this->f.vname);
  927. X
  928. X    if ((m = NewMemory()) &&
  929. X        (req = InitReq(50, 20, 255, 165, m)) &&
  930. X        SetReqBorder(req, 1, m) &&
  931. X        AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
  932. X        AddText(&gl, 0, "r(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 27, 20,
  933. X 24, 10, TRUE, m) &&
  934. X        AddText(&gl, 0, ")=", FALSE, r, EXPRLEN, TRUE, 0, RELVERIFY, 75, 20, 16
  935. X0, 10, TRUE, m) &&
  936. X        AddText(&gl, 0, "theta()=", FALSE, theta, EXPRLEN, TRUE, 0, RELVERIFY,
  937. X75, 40, 160, 10, TRUE, m) &&
  938. X        AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 51, 60
  939. X, 80, 10, TRUE, m) &&
  940. X        AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 169, 60, 8
  941. X0, 10, TRUE, m) &&
  942. X        AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 59,
  943. X 80, 32, 10, TRUE, m) &&
  944. X        AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
  945. X56, 80, 32, 10, TRUE, m) &&
  946. X        (sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
  947. X* SELECTED, 0, 11, 100, 10, 10, m)) &&
  948. X        (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
  949. Xedisc * SELECTED, 0, 11, 120, 10, 10, m)) &&
  950. X        AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 140, 65, 15, FALS
  951. XE, m) &&
  952. X        AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 140, 65, 15
  953. X, FALSE, m))
  954. X    {
  955. X        SetReqGadgets(req, gl);
  956. X        if (ret = DoRequest(req, this->f.o.g, std_ghandler))
  957. X        {
  958. X            *ref = full_refresh(this->f.o.g);
  959. X
  960. X            /* Extract info */
  961. X            this->f.min = str2double(from);
  962. X            this->f.max = str2double(to);
  963. X            this->f.steps = str2int(steps);
  964. X            if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
  965. X1;
  966. X            this->f.showdisc = (sd->Flags & SELECTED) != 0;
  967. X            this->f.nicedisc = (nd->Flags & SELECTED) != 0;
  968. X            strcpy(this->r, r);
  969. X            strcpy(this->theta, theta);
  970. X            strcpy(this->f.vname, tname);
  971. X
  972. X            /* Create function */
  973. X            destroy_r_t(this);
  974. X            if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
  975. X        }
  976. X    }
  977. X    Free(m);
  978. X
  979. X    return ret;
  980. X}
  981. X
  982. X/* Calculate points of function */
  983. Xstatic int calc_r_t(struct r_t *this, int allow_mes)
  984. X{
  985. X    double t;
  986. X    int i;
  987. X    struct graph *const g = this->f.o.g;
  988. X    double const tmin = this->f.min;
  989. X    double const tmax = this->f.max;
  990. X    int const steps = this->f.steps == INOVAL ? DEFSTEPS : this->f.steps;
  991. X    double const step = (tmax - tmin) / (steps - 1);
  992. X    static char func[FNAMELEN + 30];
  993. X
  994. X    strcpy(func, "Can't calculate points for ");
  995. X    strcat(func, this->f.o.name);
  996. X    strcat(func, ":");
  997. X
  998. X    new_list(&this->f.pts);
  999. X
  1000. X    if (!create_quick(&this->f.var))
  1001. X    {
  1002. X        if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
  1003. XL);
  1004. X        else alert(g->io.win, func, "Couldn't create variable");
  1005. X        return FALSE;
  1006. X    }
  1007. X
  1008. X    /* Calculate steps points, spread evenly from min to max */
  1009. X    for (i = 0, t = tmin; i < steps; i++, t += step)
  1010. X    {
  1011. X        point_r_t *pt = alloc_node(this->f.sizept);
  1012. X
  1013. X        if (!pt)
  1014. X        { /* No mem */
  1015. X            free_list(&this->f.pts, this->f.sizept);
  1016. X            free_quick(&this->f.var);
  1017. X            if (allow_mes) message(g, func, "No memory", (char *)NULL);
  1018. X            else alert(g->io.win, func, "No memory");
  1019. X            return FALSE;
  1020. X        }
  1021. X        add_tail(&this->f.pts, pt);
  1022. X
  1023. X        set_quick(&this->f.var, t);
  1024. X        pt->t = t;
  1025. X
  1026. X        pt->r = quick_eval(this->r_t);
  1027. X        pt->p.state = (eval_error == 0) ? EXISTS : 0;
  1028. X        if (pt->p.state == EXISTS)
  1029. X        {
  1030. X            pt->theta = quick_eval(this->theta_t);
  1031. X            pt->p.state = (eval_error == 0) ? EXISTS : 0;
  1032. X            /* Polar -> Rect conversion */
  1033. X            pt->p.x = fabs(pt->r) * cos(pt->theta);
  1034. X            pt->p.y = fabs(pt->r) * sin(pt->theta);
  1035. X        }
  1036. X    }
  1037. X    free_quick(&this->f.var);
  1038. X    return TRUE;
  1039. X}
  1040. X
  1041. X/* Try to improve look of function by adding points. If fails, decides that
  1042. X   there is a discontinuity */
  1043. X/* see f_of_x.c for details */
  1044. Xstatic struct Region *improve_r_t(struct r_t *this)
  1045. X{
  1046. X    struct graph *const g = this->f.o.g;
  1047. X    point_r_t *pt, *next;
  1048. X    int ok = FALSE, iter, abort = FALSE;
  1049. X    double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
  1050. X    double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
  1051. X    char msg[FNAMELEN + 30];
  1052. X    char pass[20];
  1053. X    struct Requester *req;
  1054. X    struct Region *full = NULL;
  1055. X
  1056. X    /* Flat has no meaning when graph incorrect */
  1057. X    if (!this->f.o.g->ok) flatx = flaty = 0.0;
  1058. X
  1059. X    if (!this->f.calc)
  1060. X    {
  1061. X        strcpy(msg, this->f.o.name);
  1062. X        strcpy(msg, "not calculated!");
  1063. X        message(g, msg, (char *)NULL);
  1064. X        return NULL;
  1065. X    }
  1066. X    if (!this->dr || !this->dtheta)
  1067. X    {
  1068. X        strcpy(msg, this->f.o.name);
  1069. X        strcat(msg, " wasn't differentiable");
  1070. X        message(g, msg, (char *)NULL);
  1071. X        return NULL;
  1072. X    }
  1073. X    if (!create_quick(&this->f.var))
  1074. X    {
  1075. X        message(g, "Couldn't create variable", (char *)NULL);
  1076. X        return NULL;
  1077. X    }
  1078. X
  1079. X    if (!(req = abort_request(g, "Improve: Pass 1")))
  1080. X        message(g, "No Memory !", (char *)NULL);
  1081. X    else
  1082. X    {
  1083. X        full = full_refresh(this->f.o.g);
  1084. X
  1085. X        for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
  1086. X        {
  1087. X            sprintf(pass, "Improve: Pass %d", iter);
  1088. X            set_abort_msg(req, pass);
  1089. X            ok = TRUE;
  1090. X
  1091. X            for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
  1092. X            {
  1093. X                if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
  1094. X                {
  1095. X                    double dr, dtheta, dt;
  1096. X
  1097. X                    pt->p.state |= OK;
  1098. X                    pt->p.state &= ~DISC;
  1099. X
  1100. X                    dt = next->t - pt->t;
  1101. X                    set_quick(&this->f.var, pt->t);
  1102. X                    dr = quick_eval(this->dr);
  1103. X                    if (eval_error == 0)
  1104. X                    {
  1105. X                        dtheta = quick_eval(this->dtheta);
  1106. X                        if (eval_error == 0)
  1107. X                        {
  1108. X                            double c = cos(pt->theta);
  1109. X                            double s = sin(pt->theta);
  1110. X                            /* A little elementary calculus ... */
  1111. X                            double dx = dr * c - pt->r * dtheta * s;
  1112. X                            double dy = dr * s + pt->r * dtheta * c;
  1113. X                            double ecartx = next->p.x - pt->p.x;
  1114. X                            double errorx = fabs(ecartx - dt * dx);
  1115. X                            double ecarty = next->p.y - pt->p.y;
  1116. X                            double errory = fabs(ecarty - dt * dy);
  1117. X
  1118. X                            /* Check both axes */
  1119. X                            if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
  1120. Xnicedisc || errorx > flatx)) ||
  1121. X                                (errory > fabs(ecarty) * MAXERROR && (!this->f.
  1122. Xnicedisc || errory > flaty)))
  1123. X                            {
  1124. X                                pt->p.state &= ~OK;
  1125. X                                ok = FALSE;
  1126. X
  1127. X                                if (iter == MAXITER) pt->p.state |= DISC;
  1128. X                                else /* cut interval in 2 */
  1129. X                                {
  1130. X                                    point_r_t *newpt = alloc_node(this->f.sizep
  1131. Xt);
  1132. X
  1133. X                                    if (!newpt)
  1134. X                                    {
  1135. X                                        nomem(g->io.win);
  1136. X                                        abort = TRUE;
  1137. X                                        break;
  1138. X                                    }
  1139. X
  1140. X                                    newpt->t = (pt->t + next->t) / 2;
  1141. X                                    set_quick(&this->f.var, newpt->t);
  1142. X
  1143. X                                    newpt->r = quick_eval(this->r_t);
  1144. X                                    newpt->p.state = (eval_error == 0) ? EXISTS
  1145. X : 0;
  1146. X                                    if (newpt->p.state == EXISTS)
  1147. X                                    {
  1148. X                                        newpt->theta = quick_eval(this->theta_t
  1149. X);
  1150. X                                        newpt->p.state = (eval_error == 0) ? EX
  1151. XISTS : 0;
  1152. X                                        newpt->p.x = fabs(newpt->r) * cos(newpt
  1153. X->theta);
  1154. X                                        newpt->p.y = fabs(newpt->r) * sin(newpt
  1155. X->theta);
  1156. X                                    }
  1157. X                                    insert(&this->f.pts, newpt, pt);
  1158. X                                }
  1159. X                            }
  1160. X                        }
  1161. X                    }
  1162. X                }
  1163. X            }
  1164. X        }
  1165. X        end_abort_request(req);
  1166. X    }
  1167. X    free_quick(&this->f.var);
  1168. X    return full;
  1169. X}
  1170. X
  1171. X/* String representation of function */
  1172. Xstatic char *f2str_r_t(struct r_t *this, char *buf, int maxlen)
  1173. X{
  1174. X    buf[maxlen - 1] = '\0';
  1175. X    strncpy(buf, this->f.o.name, maxlen - 1);
  1176. X    strncat(buf, ": r(", maxlen - strlen(buf) - 1);
  1177. X    strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  1178. X    strncat(buf, ")=", maxlen - strlen(buf) - 1);
  1179. X    strncat(buf, this->r, maxlen - strlen(buf) - 1);
  1180. X    strncat(buf, ", theta(", maxlen - strlen(buf) - 1);
  1181. X    strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  1182. X    strncat(buf, ")=", maxlen - strlen(buf) - 1);
  1183. X    strncat(buf, this->theta, maxlen - strlen(buf) - 1);
  1184. X
  1185. X    return buf;
  1186. X}
  1187. X
  1188. X/* Save local data to file */
  1189. Xstatic int save_r_t(struct r_t *this, FILE *f)
  1190. X{
  1191. X    short tag = R_T_TAG;
  1192. X    short end = R_T_END;
  1193. X
  1194. X    return WRITE(f, tag) &&
  1195. X           WRITE(f, this->r) &&
  1196. X           WRITE(f, this->theta) &&
  1197. X           WRITE(f, end);
  1198. X}
  1199. X
  1200. X/* free function */
  1201. Xstatic struct Region *delete_r_t(struct r_t *this)
  1202. X{
  1203. X    struct Region *full = full_refresh(this->f.o.g);
  1204. X
  1205. X    destroy_r_t(this);
  1206. X    FreeMem(this, sizeof(struct r_t));
  1207. X
  1208. X    return full;
  1209. X}
  1210. X
  1211. X/* Create a new function */
  1212. Xstruct r_t *new_r_t(struct graph *g, char *name)
  1213. X{
  1214. X    struct r_t *this = AllocMem(sizeof(struct r_t), MEMF_CLEAR);
  1215. X
  1216. X    if (this)
  1217. X    {
  1218. X        /* Standard init */
  1219. X        init_function(&this->f, g, name);
  1220. X        /* Local methods */
  1221. X        this->f.o.delete = (void *)delete_r_t;
  1222. X        this->f.o.edit = (void *)edit_r_t;
  1223. X        this->f.o.improve = (void *)improve_r_t;
  1224. X        this->f.o.f2str = (void *)f2str_r_t;
  1225. X        this->f.calcf = (void *)calc_r_t;
  1226. X        this->f.save = (void *)save_r_t;
  1227. X        this->f.sizept = sizeof(point_r_t);
  1228. X        return this;
  1229. X    }
  1230. X    message(g, "Couldn't create function:", "No memory", (char *)NULL);
  1231. X    return NULL;
  1232. X}
  1233. X
  1234. X/* load from file */
  1235. Xstruct r_t *load_r_t(struct graph *g, FILE *f)
  1236. X{
  1237. X    struct r_t *this = new_r_t(g, "");
  1238. X
  1239. X    if (this)
  1240. X    {
  1241. X        short end;
  1242. X
  1243. X        /* Read local data */
  1244. X        if (READ(f, this->r) &&
  1245. X            READ(f, this->theta) &&
  1246. X            READ(f, end) &&
  1247. X            end == R_T_END)
  1248. X        {
  1249. X            load_rest(&this->f, f); /* Read standard data */
  1250. X            if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
  1251. X
  1252. X            return this;
  1253. X        }
  1254. X        delete_r_t(this);
  1255. X    }
  1256. X    return NULL;
  1257. X}
  1258. X
  1259. SHAR_EOF
  1260. echo "extracting smallsym.c"
  1261. sed 's/^X//' << \SHAR_EOF > smallsym.c
  1262. X#include <exec/types.h>
  1263. X#include <exec/nodes.h>
  1264. X#include <exec/errors.h>
  1265. X#include <exec/lists.h>
  1266. X#include <exec/io.h>
  1267. X#include <exec/ports.h>
  1268. X#include <exec/memory.h>
  1269. X
  1270. X#include <intuition/preferences.h>
  1271. X#include <intuition/screens.h>
  1272. X#include <intuition/intuition.h>
  1273. X
  1274. X#include <devices/timer.h>
  1275. X#include <devices/printer.h>
  1276. X#include <devices/serial.h>
  1277. X#include <devices/clipboard.h>
  1278. X#include <devices/input.h>
  1279. X#include <devices/trackdisk.h>
  1280. X#include <devices/inputevent.h>
  1281. X#include <devices/prtgfx.h>
  1282. X
  1283. X#include <proto/console.h>
  1284. X#include <proto/diskfont.h>
  1285. X#include <proto/dos.h>
  1286. X#include <proto/exec.h>
  1287. X#include <proto/intuition.h>
  1288. X#include <proto/graphics.h>
  1289. X#include <proto/icon.h>
  1290. X#include <proto/layers.h>
  1291. X#include <proto/timer.h>
  1292. X
  1293. X#include <libraries/dos.h>
  1294. X#include <libraries/dosextens.h>
  1295. X#include <libraries/diskfont.h>
  1296. X
  1297. X#include <workbench/startup.h>
  1298. X#include <workbench/workbench.h>
  1299. X
  1300. X#include <graphics/regions.h>
  1301. X#include <graphics/gfxmacros.h>
  1302. X#include <graphics/rastport.h>
  1303. X#include <graphics/layers.h>
  1304. X#include <graphics/gfx.h>
  1305. X#include <graphics/text.h>
  1306. X#include <graphics/clip.h>
  1307. SHAR_EOF
  1308. echo "extracting tracker.c"
  1309. sed 's/^X//' << \SHAR_EOF > tracker.c
  1310. X/* Resource tracking routines, by Karl Lehenbauer
  1311. X   Lattice version by David Gay.
  1312. X   This code is in the public domain
  1313. X*/
  1314. X
  1315. X/* tracking memory allocator */
  1316. X
  1317. X#include <exec/types.h>
  1318. X#include <exec/memory.h>
  1319. X#include <stdio.h>
  1320. X#include <string.h>
  1321. X
  1322. X#include <proto/exec.h>
  1323. X#include <proto/dos.h>
  1324. X
  1325. X/* comment out the following line if you want locks freed twice reported
  1326. X * at the cost of getting spurious resource error messages when
  1327. X * reusing the lock */
  1328. X/* #define FORGET_LOCKS_WHEN_UNLOCKED */
  1329. X
  1330. X/* comment out the following line if you want memory freed twice reported
  1331. X * at the cost of getting spurious resource error messages when
  1332. X * freeing and reallocating memory */
  1333. X#define FORGET_MEMORY_WHEN_FREED
  1334. X
  1335. X/* make sure our invocations of the real routines on behalf of the user
  1336. X   don't cause us to recurse */
  1337. X
  1338. X#ifdef AllocMem
  1339. X#undef AllocMem
  1340. X#undef FreeMem
  1341. X#undef AllocSignal
  1342. X#undef FreeSignal
  1343. X#undef Lock
  1344. X#undef UnLock
  1345. X#undef DupLock
  1346. X#undef ParentDir
  1347. X#endif
  1348. X
  1349. X/* my flags */
  1350. X#define FREED_IT 1
  1351. X
  1352. Xstruct TrackingAllocMemData
  1353. X{
  1354. X    UBYTE *where;             /* address returned by allocator */
  1355. X    long amount;             /* number of bytes allocated */
  1356. X    long alloc_flags;         /* flags passed to allocator */
  1357. X    char *file;         /* filename of caller from the macro */
  1358. X    int line;                 /* line number of caller from macro */
  1359. X    long my_flags;             /* flags internal to tracker */
  1360. X    struct TrackingAllocMemData *next;    /* pointer to next entry */
  1361. X};
  1362. X
  1363. Xstruct TrackingAllocMemData *TrackingAllocMemList = NULL;
  1364. Xlong MemAllocCount = 0, MemFreeCount = 0;
  1365. X
  1366. Xvoid *TrackingAllocMem(amount,flags,file,line)
  1367. Xlong amount;
  1368. Xlong flags;
  1369. Xchar *file;
  1370. Xint line;
  1371. X{
  1372. X    struct TrackingAllocMemData *rp;
  1373. X    UBYTE *users_memory;
  1374. X
  1375. X    /* perform the actual alloc */
  1376. X    users_memory = AllocMem(amount,flags);
  1377. X
  1378. X    /* if it succeeded, record tracking info */
  1379. X    if (users_memory)
  1380. X    {
  1381. X         MemAllocCount++;
  1382. X
  1383. X         if ((rp = AllocMem((long)sizeof(struct TrackingAllocMemData),0L)) == N
  1384. XULL)
  1385. X             fprintf(stderr, "tracker: can't alloc memory to record AllocMem da
  1386. Xta");
  1387. X
  1388. X         /* add new alloc data entry to linked list */
  1389. X         rp->next = TrackingAllocMemList;
  1390. X         TrackingAllocMemList = rp;
  1391. X
  1392. X         /* shove in save values */
  1393. X         rp->amount = amount;
  1394. X         rp->alloc_flags = flags;
  1395. X         rp->where = users_memory;
  1396. X         rp->file = file;
  1397. X         rp->line = line;
  1398. X         rp->my_flags = 0;
  1399. X    }
  1400. X    /* return pointer to the space allocated */
  1401. X    return(users_memory);
  1402. X}
  1403. X
  1404. Xvoid TrackingFreeMem(where,amount,file,line)
  1405. XUBYTE *where;
  1406. Xlong amount;
  1407. Xchar *file;
  1408. Xint line;
  1409. X{
  1410. X    struct TrackingAllocMemData *rp, *op, *freep;
  1411. X
  1412. X    MemFreeCount++;
  1413. X    /* scan the memory tracking list for a match */
  1414. X    for (rp = TrackingAllocMemList, op = NULL; rp != NULL; op = rp, rp = rp->ne
  1415. Xxt)
  1416. X    {
  1417. X         /* if we matched the address */
  1418. X         if (rp->where == where)
  1419. X         {
  1420. X             /* if they got the amount wrong, tell them */
  1421. X             if (rp->amount != amount)
  1422. X             {
  1423. X                 fprintf(stderr,"freed addr %lx OK but length differs, talloc'e
  1424. Xd %ld, freed %ld,\n\tallocated at file %s line %d, freed at file %s line %d\n",
  1425. X                 where,rp->amount,amount,rp->file,rp->line,file,line);
  1426. X             }
  1427. X#ifndef FORGET_MEMORY_WHEN_FREED
  1428. X             /* if it's already free, tell them they freed twice */
  1429. X             if (rp->my_flags & FREED_IT)
  1430. X             {
  1431. X                 fprintf(stderr,"freed memory twice at %lx, amount %ld,\n\tallo
  1432. Xcated in file %s at line %d, freed in file %s at line %d\n",where,amount,rp->fil
  1433. Xe,rp->line,file,line);
  1434. X                 return;
  1435. X             }
  1436. X             else
  1437. X             {
  1438. X                 /* mark this entry as free */
  1439. X                 rp->my_flags |= FREED_IT;
  1440. X             }
  1441. X#else
  1442. X             /* remove entry from linked list and free it */
  1443. X             if (op != NULL) op->next = rp->next;
  1444. X             else
  1445. X                 TrackingAllocMemList = rp->next;
  1446. X             freep = rp;
  1447. X             rp = rp->next;
  1448. X             FreeMem(freep,(long)sizeof(struct TrackingAllocMemData));
  1449. X#endif
  1450. X             /* Munge memory block */
  1451. X             memset((char *)where, amount, 3); /* Set to an odd number ... */
  1452. X             FreeMem(where,(long)amount);
  1453. X
  1454. X             return;
  1455. X         }
  1456. X    }
  1457. X    fprintf(stderr,"Freed memory at %lx of amount %ld that wasn't allocated,\n\
  1458. Xtfreed at file %s line %d\n",where,amount,file,line);
  1459. X    FreeMem(where,amount);
  1460. X}
  1461. X
  1462. Xvoid ReportUnfreedMemory()
  1463. X{
  1464. X    struct TrackingAllocMemData *rp = TrackingAllocMemList, *freep;
  1465. X
  1466. X    while (rp != NULL)
  1467. X    {
  1468. X         if (!(rp->my_flags & FREED_IT))
  1469. X         {
  1470. X             fprintf(stderr,"FreeMem was never called for memory at %lx, amount
  1471. X %ld,\n\tthe alloc was performed at file %s line %d\n",rp->where,rp->amount,rp->
  1472. Xfile,rp->line);
  1473. X         }
  1474. X         freep = rp;
  1475. X         rp = rp->next;
  1476. X         FreeMem(freep,(long)sizeof(struct TrackingAllocMemData));
  1477. X    }
  1478. X    printf("Total tracked AllocMem calls %ld, FreeMem calls %ld\n",MemAllocCoun
  1479. Xt,MemFreeCount);
  1480. X}
  1481. X
  1482. X
  1483. X/* track signals */
  1484. X/* tracking AllocSignal doesn't currently track where it was called from */
  1485. X
  1486. Xlong TrackingSignalMask = 0;
  1487. Xlong SignalAllocCount = 0, SignalFreeCount = 0;
  1488. X
  1489. Xlong TrackingAllocSignal(signal_num,file,line)
  1490. Xlong signal_num;
  1491. Xchar *file;
  1492. Xint line;
  1493. X{
  1494. X    SignalAllocCount++;
  1495. X
  1496. X    signal_num = AllocSignal(signal_num);
  1497. X
  1498. X    if (signal_num != -1)
  1499. X         TrackingSignalMask |= (1 << signal_num);
  1500. X
  1501. X    return(signal_num);
  1502. X}
  1503. X
  1504. Xvoid TrackingFreeSignal(signal_num,file,line)
  1505. Xlong signal_num;
  1506. Xchar *file;
  1507. Xint line;
  1508. X{
  1509. X    SignalFreeCount++;
  1510. X
  1511. X    if (!(TrackingSignalMask & (1 << signal_num)))
  1512. X    {
  1513. X         fprintf(stderr, "freed a signal (%ld) that was never allocated, at fil
  1514. Xe %s line %d\n",
  1515. X             signal_num,file,line);
  1516. X    }
  1517. X    TrackingSignalMask &= ~(1 << signal_num);
  1518. X}
  1519. X
  1520. Xvoid ReportUnfreedSignals()
  1521. X{
  1522. X    if (TrackingSignalMask)
  1523. X         fprintf(stderr, "failed to free signals indicated by this mask: %8lx\n
  1524. X",
  1525. X             TrackingSignalMask);
  1526. X    printf("Total tracked AllocSignal calls %ld, FreeSignal calls %ld\n",Signal
  1527. XAllocCount,SignalFreeCount);
  1528. X}
  1529. X
  1530. X/* tracking lock and unlock */
  1531. X
  1532. Xstruct TrackingLockData
  1533. X{
  1534. X    BPTR lock;    /* lock returned by Lock */
  1535. X    char *name;         /* name of file that was locked */
  1536. X    long accessMode;         /* access mode of the file that was locked */
  1537. X    char *file;         /* ptr to file name of line of caller */
  1538. X    int line;                 /* ptr to line number text of locker */
  1539. X    long my_flags;             /* flags internal to tracker */
  1540. X    struct TrackingLockData *next;    /* pointer to next entry */
  1541. X};
  1542. X
  1543. X/* flags */
  1544. X#define CREATED_BY_DUPLOCK 1
  1545. X
  1546. Xstruct TrackingLockData *TrackingLockList = NULL;
  1547. Xlong TrackerLockCount = 0, TrackerUnLockCount = 0;
  1548. X
  1549. XBPTR TheTrackingLock(name, accessMode, file, line)
  1550. Xchar *name;
  1551. Xlong accessMode;
  1552. Xchar *file;
  1553. Xint line;
  1554. X{
  1555. X    struct TrackingLockData *lp;
  1556. X    BPTR users_lock;
  1557. X
  1558. X    users_lock = Lock(name, (long)accessMode);
  1559. X
  1560. X    if (users_lock)
  1561. X    {
  1562. X         TrackerLockCount++;
  1563. X
  1564. X         if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  1565. X     
  1566. X             fprintf(stderr, "tracker: can't alloc memory to record lock data")
  1567. X;
  1568. X
  1569. X         /* add new alloc data entry to linked list */
  1570. X         lp->next = TrackingLockList;
  1571. X         TrackingLockList = lp;
  1572. X
  1573. X         /* shove in save values */
  1574. X         lp->accessMode = accessMode;
  1575. X         lp->file = file;
  1576. X         lp->line = line;
  1577. X         lp->my_flags = 0;
  1578. X         lp->lock = users_lock;
  1579. X
  1580. X         /* alloc space for filename and save */
  1581. X         if ((lp->name = AllocMem((long)(strlen(name)+1),0L)) == NULL)
  1582. X             fprintf(stderr, "tracker: can't alloc memory to record lock filena
  1583. Xme");
  1584. X         strcpy(lp->name,name);
  1585. X    }
  1586. X    return(users_lock);
  1587. X}
  1588. X
  1589. XBPTR TheTrackingDupLock(lock, file, line)
  1590. XBPTR lock;
  1591. Xchar *file;
  1592. Xint line;
  1593. X{
  1594. X    struct TrackingLockData *lp;
  1595. X    BPTR users_lock;
  1596. X
  1597. X    users_lock = DupLock(lock);
  1598. X
  1599. X    if (users_lock)
  1600. X    {
  1601. X         TrackerLockCount++;
  1602. X
  1603. X         if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  1604. X     
  1605. X             fprintf(stderr, "tracker: can't alloc memory to record lock data")
  1606. X;
  1607. X
  1608. X         /* add new alloc data entry to linked list */
  1609. X         lp->next = TrackingLockList;
  1610. X         TrackingLockList = lp;
  1611. X
  1612. X         lp->file = file;
  1613. X         lp->line = line;
  1614. X         lp->name = NULL;
  1615. X         lp->lock = users_lock;
  1616. X         lp->my_flags = CREATED_BY_DUPLOCK;
  1617. X    }
  1618. X    return(users_lock);
  1619. X}
  1620. X
  1621. Xvoid TheTrackingUnLock(lock,file,line)
  1622. XBPTR lock;
  1623. Xchar *file;
  1624. Xint line;
  1625. X{
  1626. X    struct TrackingLockData *lp, *op, *freep;
  1627. X
  1628. X    TrackerUnLockCount++;
  1629. X
  1630. X    /* scan the lock tracking list for a match */
  1631. X    for (lp = TrackingLockList, op = NULL; lp != NULL; op = lp, lp = lp->next)
  1632. X    {
  1633. X         /* if we matched the lock */
  1634. X         if (lp->lock == lock)
  1635. X         {
  1636. X#ifndef FORGET_LOCKS_WHEN_UNLOCKED
  1637. X             /* if it's already free, tell them they freed twice */
  1638. X             if (lp->my_flags & FREED_IT)
  1639. X             {
  1640. X                 fprintf(stderr,"freed lock twice, lock %lx, filename %s\n\tloc
  1641. Xked at file %s line %d, freed at file %s line %d\n",lock,lp->name,lp->file,lp->l
  1642. Xine,file,line);
  1643. X                 return;
  1644. X             }
  1645. X             else
  1646. X             {
  1647. X                 /* mark this entry as free */
  1648. X                 lp->my_flags |= FREED_IT;
  1649. X             }
  1650. X#else
  1651. X             if (op != NULL) op->next = lp->next;
  1652. X             else TrackingLockList = lp->next;
  1653. X             freep = lp;
  1654. X             lp = lp->next;
  1655. X             if (lp->name != NULL)
  1656. X                 FreeMem(lp->name,(long)(strlen(lp->name)+1));
  1657. X             FreeMem(freep,(long)(sizeof(struct TrackingLockData)));
  1658. X#endif
  1659. X             UnLock(lock);
  1660. X             return;
  1661. X         }
  1662. X    }
  1663. X    fprintf(stderr,"Freed lock %lx that hadn't been allocated at file %s line %
  1664. Xd\n",lock,file,line);
  1665. X}
  1666. X
  1667. XBPTR TheTrackingParentDir(BPTR lock, char *file, int line)
  1668. X{
  1669. X    struct TrackingLockData *lp;
  1670. X    BPTR users_lock;
  1671. X
  1672. X    users_lock = ParentDir(lock);
  1673. X
  1674. X    if (users_lock)
  1675. X    {
  1676. X         TrackerLockCount++;
  1677. X
  1678. X         if ((lp = AllocMem((long)sizeof(struct TrackingLockData),0L)) == NULL)
  1679. X     
  1680. X             fprintf(stderr, "tracker: can't alloc memory to record lock data")
  1681. X;
  1682. X
  1683. X         /* add new alloc data entry to linked list */
  1684. X         lp->next = TrackingLockList;
  1685. X         TrackingLockList = lp;
  1686. X
  1687. X         /* shove in save values */
  1688. X         lp->accessMode = 0;
  1689. X         lp->file = file;
  1690. X         lp->line = line;
  1691. X         lp->my_flags = 0;
  1692. X         lp->lock = users_lock;
  1693. X         lp->name = NULL;
  1694. X    }
  1695. X    return(users_lock);
  1696. X}
  1697. X
  1698. Xvoid ReportUnfreedLocks()
  1699. X{
  1700. X    struct TrackingLockData *lp = TrackingLockList, *freep;
  1701. X
  1702. X    while (lp != NULL)
  1703. X    {
  1704. X         if (!(lp->my_flags & FREED_IT))
  1705. X         {
  1706. X             if (lp->my_flags & CREATED_BY_DUPLOCK)
  1707. X             {
  1708. X                 fprintf(stderr,"UnLock was never called for lock %lx,\n\It was
  1709. X created by DupLock at file %s line %d\n",lp->lock,lp->file,lp->line);
  1710. X             }
  1711. X             else
  1712. X             {
  1713. X                 fprintf(stderr,"UnLock was never called for lock %lx,\n\It was
  1714. X created by a Lock of %s\nat file %s line %d\n",lp->lock,lp->name,lp->file,lp->l
  1715. Xine);
  1716. X             }
  1717. X         }
  1718. X         if (lp->name != NULL)
  1719. X             FreeMem(lp->name,(long)(strlen(lp->name)+1));
  1720. X         freep = lp;
  1721. X         lp = lp->next;
  1722. X         FreeMem(freep,(long)sizeof(struct TrackingLockData));
  1723. X    }
  1724. X    printf("Total tracked Lock and DupLock calls %ld, UnLock calls %ld\n",Track
  1725. XerLockCount,TrackerUnLockCount);
  1726. X}
  1727. X
  1728. Xvoid TrackerExitReport()
  1729. X{
  1730. X    ReportUnfreedMemory();
  1731. X    ReportUnfreedLocks();
  1732. X    ReportUnfreedSignals();
  1733. X}
  1734. SHAR_EOF
  1735. echo "extracting tracker.h"
  1736. sed 's/^X//' << \SHAR_EOF > tracker.h
  1737. X/* Resource tracking routines, by Karl Lehenbauer
  1738. X   Lattice version by David Gay.
  1739. X   This code is in the public domain
  1740. X*/
  1741. X
  1742. X#ifdef DEBUG
  1743. X/* tracking macros to use tracker routines */
  1744. X
  1745. X#define AllocMem(x,y) TrackingAllocMem((x),(y),__FILE__,__LINE__)
  1746. X#define FreeMem(x,y) TrackingFreeMem((x),(y),__FILE__,__LINE__)
  1747. X
  1748. X#define AllocSignal(x) TrackingAllocSignal((x),__FILE__,__LINE__)
  1749. X#define FreeSignal(x) TrackingFreeSignal((x),__FILE__,__LINE__);
  1750. X
  1751. X#define Lock(x,y) TheTrackingLock((x),(y),__FILE__,__LINE__);
  1752. X#define UnLock(x) TheTrackingUnLock((x),__FILE__,__LINE__);
  1753. X#define DupLock(x) TheTrackingDupLock((x),__FILE__,__LINE__);
  1754. X#define ParentDir(x) TheTrackingParentDir((x),__FILE__,__LINE__);
  1755. X
  1756. Xvoid *TrackingAllocMem(long amount, long flags, char *file, int line);
  1757. Xvoid TrackingFreeMem(void *where, long amount, char *file, int line);
  1758. X
  1759. Xlong TrackingAllocSignal(long signal_num, char *file, int line);
  1760. Xvoid TrackingFreeSignal(long signal_num, char *file, int line);
  1761. X
  1762. Xvoid *TrackingAllocRaster();
  1763. Xvoid TrackingFreeRaster();
  1764. X
  1765. XBPTR TheTrackingLock(char *name, long accessMode, char *file, int line);
  1766. XBPTR TheTrackingDupLock(BPTR lock, char *file, int line);
  1767. Xvoid TheTrackingUnLock(BPTR lock, char *file, int line);
  1768. XBPTR TheTrackingParentDir(BPTR lock, char *file, int line);
  1769. X
  1770. Xvoid TrackerExitReport(void);
  1771. X
  1772. X#endif
  1773. X
  1774. SHAR_EOF
  1775. echo "extracting tracker.readme"
  1776. sed 's/^X//' << \SHAR_EOF > tracker.readme
  1777. X[even though in an alpha state, I think this will be of great use to
  1778. X Aztec C programmers who want to be sure they're freeing all of their
  1779. X memory -karl]
  1780. X
  1781. X
  1782. XC Programmer's Amiga Resource Tracking Routines    Version 0.0a   1/5/89
  1783. X-------------------------------------------------------------------------
  1784. X
  1785. XThis code and documentation is released to the Public Domain without any
  1786. Xrestrictions on use, resale or redistribution.
  1787. X
  1788. XNo license or warranty of appropriateness, usefulness or bug-freeness is
  1789. Xexpressed or implied.   This is free code.  We don't have a contract.
  1790. X
  1791. XWritten by:
  1792. X
  1793. XKarl Lehenbauer, Hackercorp, 3918 Panorama, Missouri City, TX, USA  77459
  1794. X(713) 438-4964 voice,  (713) 438-5018 data
  1795. XUsenet: uunet!sugar!karl, Internet: karl@sugar.uu.net, BIX: kelehen
  1796. X
  1797. X
  1798. XThese routines were written to aid C programmers in insuring that their
  1799. Xprograms are  properly returning all the memory, signals and locks they
  1800. Xhave allocated.
  1801. X
  1802. XTo use them, include tracker.h in your C source programs and recompile.
  1803. X(The use of an "includes.c" along with the Manx +i and +h flags to
  1804. Xprecompile the symbol table obviates the necessity of editing
  1805. X'#include "tracker.h"' into every one of your source files.)
  1806. XNext, edit your exit routine to call TrackerExitReport() after it has
  1807. Xfreed everything.  Then, compile tracker.c using the memory model you're
  1808. Xusing for the rest of your code and link your program to include tracker.o.
  1809. X(This can all be done in your makefile if you've got it set up right.)
  1810. XFinally, run your program.
  1811. X
  1812. XThe program must either be initiated from the CLI or you must edit your
  1813. Xprogram's startup code to fopen stderr and direct it somewhere  (like
  1814. Xto a  window or a file) or you won't get any of the resource tracker's
  1815. Xmessages, or worse.
  1816. X
  1817. XAs your program runs, every time it allocs memory via AllocMem(), allocs
  1818. Xa signal via AllocSignal() or gets a Lock via Lock(), special tracking
  1819. Xroutines execute instead (thanks to some macros defined by tracker.h)
  1820. Xwhich, in addition to performing the action you requested, record
  1821. Xinformation about what you requested and what you got.  For AllocMem(),
  1822. Xthe source file and line of the AllocMem call as well as the amount of memory
  1823. Xrequested and the pointer to the memory returned are recorded.  For
  1824. XAllocSignal(), only the signal numbers allocated are recorded at this time.
  1825. XFor Lock(), the file name to be locked, source file and line number and
  1826. Xthe lock returned are recorded.
  1827. X
  1828. XWhen your program frees memory via FreeMem(), a special tracking version
  1829. Xof FreeMem is executed that searches the list of entries recorded by the
  1830. Xtracking version of AllocMem().  The resource tracker reports if you free
  1831. Xsomething more than once, if you free something that you didn't allocate
  1832. Xor if the length that you are freeing differes from what you allocated.
  1833. XThis includes the source file name and line number of the matching AllocMem
  1834. X(when it is known) and always includes the source file and line for FreeMem.
  1835. X
  1836. XWhen your program frees a signal via FreeSignal(), a tracking version
  1837. Xof FreeSignal checks to see if you have allocated the signal you are
  1838. Xnow freeing.  If you haven't, it reports it, but it doesn't include the
  1839. Xfile name and line number at this time.  I don't think this is a serious
  1840. Xproblem, as signals aren't as critical as the other stuff, but I may add
  1841. Xit in a future version.
  1842. X
  1843. XWhen your program unlocks a lock via UnLock(), a tracking version of UnLock
  1844. Xsearches the list of recorded locks to see if you locked the lock you are
  1845. Xunlocking and report accordingly.
  1846. X
  1847. XThe tracker exit report provided by TrackerExitReport() is where most of
  1848. Xthe bugs are identified.  TrackerExitReport identifies all AllocMems that
  1849. Xdidn't have a corresponding FreeMem, including the source file and line
  1850. Xof the call to AllocMem as well as the address and size of the memory
  1851. Xin question.  The resource tracker does not free the memory for you because
  1852. Xyou may have not freed the memory on purpose (for example, you may have
  1853. Xspawned a task that uses it will free it later) and it cannot know that.
  1854. X
  1855. XThe exit report details all signals that weren't freed.  This isn't very
  1856. Ximportant, in my opinion.
  1857. X
  1858. XAlso, the exit report prints information on all file locks that were made
  1859. Xthat didn't have a corresponding UnLock.  This information includes the
  1860. Xname of the file, value of the lock and the source file and line of the
  1861. Xcode that locked it.
  1862. X
  1863. XThe exit report also prints the number of calls to allocate and free memory,
  1864. Xallocate and free signals and to lock and unlock files as a gross indicator
  1865. Xof whether you're cleaning everything up properly.
  1866. X
  1867. XNote that, in the default configuration, memory that is freed and
  1868. Xreallocated will screw up the tracker because the tracker continues
  1869. Xto track memory objects after they have been  freed. This is a tradeoff
  1870. Xbetween being to be able to detect multiple frees of the same memory or
  1871. Xnot.  If that's a problem, tracker.c can be recompiled with a
  1872. X-DFORGET_MEMORY_WHEN_FREED option so that it will not try to detect
  1873. Xmultiple frees.
  1874. X
  1875. XThe same is true for the lock tracking routines, although in that case
  1876. Xthe argument is more clear that unlocks should cause the lock tracking
  1877. Xentry to be discarded, because multiple unlocks are common and multiple
  1878. Xlocks and unlocks of the same file  during execution are also conceivably
  1879. Xpretty common.  Right now by default, the tracker will track locks after
  1880. Xthey have been freed.   To change this behavior, recompile tracker.c with
  1881. Xthe -DFORGET_LOCKS_WHEN_UNLOCKED option.
  1882. X
  1883. XUnfortunately, the tracker macros that redefine AllocMem and such will
  1884. Xcause your compiler to barf on any files you have that declare them
  1885. Xas external.  If that happens, either remove the external declarations
  1886. X(and include <functions.h>) or move them to be before the include of
  1887. Xtracker.h.
  1888. X
  1889. X
  1890. XALPHA RELEASE, SOFTWARE STATUS
  1891. X------------------------------
  1892. X
  1893. XThe Lock, Unlock and DupLock tracking routines have not been tested
  1894. Xadequately.  The signal stuff works OK, but that's no biggie.  The
  1895. Xmain thing of interest is the tracking AllocMem and FreeMem, which
  1896. XI have used successfully on several programs that I have been working
  1897. Xon.
  1898. X
  1899. X-karl @ The Hacker's Haven, Houston, TX -- 5-Jan-89
  1900. X
  1901. XP.S.  Note that TrackerExitReport() must be called to get the tracking
  1902. X routines to free the memory they have allocated, so it's a good idea
  1903. X to call it from your abnormal exit (_abort, etc) routines as well as
  1904. X normal exit.   Also, that's good because you can make sure you're freeing
  1905. X properly from your strange abort conditions, a thing that's hard to get
  1906. X right.
  1907. SHAR_EOF
  1908. echo "End of archive 6 (of 7)"
  1909. # if you want to concatenate archives, remove anything after this line
  1910. exit
  1911.